/*
<div id = "app">hello {{msg}}</div>

区别:
ast 语法树是一个对象，它可以操作节点、css、js
虚拟DOM只能操作节点

{
    tag:'div',
        attrs:[{id:"app"}],
    children:[{tag:null,text:hello,{tag:'div'}}]
}
*/

// ast正则
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*` // 标签名称
const qnameCapture = `((?:${ncname}\\:)?${ncname})`;  // 处理 <span :xx>
const startTagOpen = new RegExp(`^<${qnameCapture}`); // 开头标签
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`); // 标签结尾
const startTagClose = /^\s*(\/?)>/;  // 匹配标签结束的  {{ }}
const attribute = /^\s*([^\s"'<>/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;  // 属性标签
const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g;  // 默认标签

// 根据开始标签、文本、结束标签 来创建ast语法树
// <div id = "app"> hello {msg} <span>world</span> </div>
function createASTElement(tag, attrs) {
    return {
        tag: tag, // div
        attrs: attrs, //
        children: [], // 子节点
        type: 1,
        parent: null, // 父节点
    }
}

let root; // 根元素

let createParent; // 当前元素的父元素

// 数据结构栈 （管理标签的先后顺序）
let stack = []

// 开始标签
function start(tag, attrs) {
    // console.log('开始标签:', tag, attrs)
    let element = createASTElement(tag, attrs);
    if (!root) { // 没有根元素，找一个开始标签
        root = element
    }
    createParent = element
    stack.push(element)
}

// 获取文本
function charts(text) {
    // console.log('获取文本:', text)
    // 空格替换
    text = text.replace(/a/g, '')
    if (text) {
        createParent.children.push({
            type: 3,
            text
        })
    }
}

// 结束标签
function end(tag) {
    // console.log('结束标签:', tag)
    let element = stack.pop() // 出栈，拿到最后一个元素
    createParent = stack[stack.length - 1]
    if (createParent) {  // 标签的闭合
        element.parent = createParent.tag
        createParent.children.push(element)
    }
}

// 解析HTML标签
export function parseHTML(html) {
    while (html) {
        let textEnd = html.indexOf('<') // 0

        if (textEnd === 0) { // 标签
            // 开始标签
            const startTagMatch = parseStartTag() // 开始标签内容  {}
            if (startTagMatch) {
                start(startTagMatch.tagName, startTagMatch.attrs)
                continue
            }
            // 结束标签
            let endTagMatch = html.match(endTag)
            if (endTagMatch) {
                advance(endTagMatch[0].length)
                end(endTagMatch[1])
                continue
            }
        }

        // 文本
        let text
        if (textEnd > 0) {
            // 解析文本
            // 获取文本
            //  console.log(textEnd)   // 14
            text = html.substring(0, textEnd)
        }
        if (text) {
            advance(text.length)
            charts(text)
        }
    }

    function parseStartTag() {
        const start = html.match(startTagOpen) // 返回 boolean

        if (start) {
            // 创建语法树
            let match = {
                tagName: start[1],
                attrs: [],
            }

            // 删除开始标签
            advance(start[0].length)

            // 注意多个遍历  注意 >
            let attr
            let end  // 去掉 >hello,{{msg}}</div>  中的  >
            while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
                //console.log(attr)
                match.attrs.push({name: attr[1], value: attr[3] || attr[4] || attr[5]})
                advance(attr[0].length)
            }

            if (end) {
                //console.log(end)
                advance((end[0].length))
                return match
            }
        }


    }

    // 删除元素
    function advance(n) {
        html = html.substring(n)
        // console.log('删除元素:', html)
    }

    // console.log('root:', root)
    return root
}
